#include <iostream>

template <typename Vector>
class VectorIterator
{

public:
    using ValueType = typename Vector::ValueType;
    VectorIterator(ValueType *ptr) : m_Ptr(ptr) {}

    VectorIterator &operator++()
    {
        m_Ptr++;
        return *this;
    }

    VectorIterator operator++(int)
    {
        VectorIterator iterator = *this;
        ++(*this);
        return iterator;
    }

    VectorIterator &operator--()
    {
        m_Ptr--;
        return *this;
    }

    VectorIterator &operator--(int)
    {
        VectorIterator iterator = *this;
        --(*this);
        return iterator;
    }

    ValueType &operator[](int index)
    {
        return *(m_Ptr + index);
    }

    ValueType &operator->()
    {
        return m_Ptr;
    }

    ValueType &operator*()
    {
        return *m_Ptr;
    }

    bool operator==(const VectorIterator &other) const
    {
        return m_Ptr == other.m_Ptr;
    }

    bool operator!=(const VectorIterator &other) const
    {
        return !(*this == other);
    }

private:
    ValueType *m_Ptr;
};

template <typename T>
class Vector
{

public:
    using ValueType = T;
    using Iterator = VectorIterator<Vector<T>>;

public:
    Vector()
    {
        ReAlloc(2);
    }

    ~Vector()
    {
        Clear();
        ::operator delete(m_Data, m_Capacity * sizeof(T));
    }

    /*
    //利用模板合并
    void PushBack(const T& value)
    {
       if(m_Size >= m_Capacity)
          ReAlloc(m_Capacity + m_Capacity / 2);

       m_Data[m_Size] = value;
       m_Size++;
    }

    void PushBack(T&& value)
    {
       if(m_Size >= m_Capacity)
          ReAlloc(m_Capacity + m_Capacity / 2);

       m_Data[m_Size] = std::move(value);
       m_Size++;
    }

   */

    template <typename U>
    void PushBack(U &&value)
    {
        if (m_Size >= m_Capacity)
            ReAlloc(m_Capacity + m_Capacity / 2);

        m_Data[m_Size] = value;
        m_Size++;
    }

    /*
    可变参数模板 typename... Args 来接收任意数量和类型的参数。Args&&... args 是一个通用引用，它可以匹配左值和右值。
    然后，我们使用 std::forward<Args>(args)... 将参数以原始类型传递给 T 的构造函数。
    这样，我们可以直接在容器中构造对象，避免额外的拷贝和移动操作。
    */
    template <typename... Types> // 支持可变参数模板
    T &EmplaceBack(Types &&...type)
    {
        if (m_Size >= m_Capacity)
            ReAlloc(m_Capacity + m_Capacity / 2);

        // m_Data[m_Size] =  T(std::forward<Types>(type)...);
        new (&m_Data[m_Size]) T(std::forward<Types>(type)...);
        return m_Data[m_Size++];
    }

    /*
     1. &m_Data[m_Size]：这是一个指向容器中下一个空闲位置的指针。我们将在这个位置上构造新的对象。

     2. new(...) T(...)：这是一个定位 new 表达式，它允许我们在指定的内存位置上直接构造对象。在这个例子中，我们将在 m_Data[m_Size] 的位置上构造一个 T 类型的对象。

     3. std::forward<Args>(args)...：这是一个完美转发表达式，它将 EmplaceBack 函数接收到的参数以原始类型（左值或右值）传递给 T 的构造函数。这样，我们可以避免不必要的拷贝和移动操作，提高代码性能。

     综上所述，new(&m_Data[m_Size]) T(std::forward<Args>(args)...); 这行代码的作用是在容器中的下一个空闲位置上直接构造一个新的对象，同时使用完美转发将参数传递给对象的构造函数。
    */

    void PopBack()
    {
        if (m_Size > 0)
        {
            m_Size--;
            m_Data[m_Size].~T();
        }
    }

    void Clear()
    {
        for (int i = 0; i < m_Size; i++)
        {
            m_Data[i].~T();
        }

        m_Size = 0;
    }

    const T &operator[](size_t index) const
    {
        if (index >= m_Size)
            std::out_of_range("index is out of size");

        return m_Data[index];
    }

    T &operator[](size_t index)
    {
        if (index >= m_Size)
            std::out_of_range("index is out of size");

        return m_Data[index];
    }

    size_t Size() const
    {
        return m_Size;
    }

    Iterator begin()
    {
        return Iterator(m_Data);
    }

    Iterator end()
    {
        return Iterator(m_Data + m_Size);
    }

private:
    void ReAlloc(size_t newCapacity)
    {
        // T* newBlock = new T[newCapacity];
        T *newBlock = (T *)::operator new(newCapacity * sizeof(T));

        if (m_Size > newCapacity)
        {
            m_Size = newCapacity;
        }

        for (int i = 0; i < m_Size; i++)
        {
            // newBlock[i] = std::move(m_Data[i]);
            new (&newBlock[i]) T(std::move(m_Data[i]));
        }

        for (int i = 0; i < m_Size; i++)
        {
            m_Data[i].~T();
        }

        ::operator delete(m_Data, m_Capacity * sizeof(T));
        m_Data = newBlock;
        m_Capacity = newCapacity;
    }

private:
    T *m_Data = nullptr; // 别忘了变量初始化
    size_t m_Capacity = 0;
    size_t m_Size = 0;
};

struct Object
{
    float x = 0.0f, y = 0.0f, z = 0.0f;
    int *m_MemoryBlock = nullptr;

    Object() { m_MemoryBlock = new int[5]; }
    ~Object()
    {
        std::cout << "Destroy Object!" << std::endl;
        if (m_MemoryBlock)
        {
            delete[] m_MemoryBlock;
            m_MemoryBlock = nullptr;
        }
    }

    Object(float scalar) : x(scalar), y(scalar), z(scalar)
    {
        m_MemoryBlock = new int[5];
    }
    Object(float x, float y, float z) : x(x), y(y), z(z)
    {
        m_MemoryBlock = new int[5];
    }

    Object(const Object &object) : x(object.x), y(object.y), z(object.z)
    {
        std::cout << "Copy !" << std::endl;
    }

    Object(Object &&object) : x(object.x), y(object.y), z(object.z) // 移动构造不要带const
    {
        std::cout << "Object Move!" << std::endl;
    }

    Object &operator=(const Object &other)
    {
        std::cout << "Copy Assgin!" << std::endl;
        x = other.x;
        y = other.y;
        z = other.z;

        return *this;
    }

    Object &operator=(Object &&other) // 移动赋值不要带const
    {
        std::cout << "Move Assgin!" << std::endl;
        x = other.x;
        y = other.y;
        z = other.z;

        return *this;
    }
};

template <typename T>
void PrintVector(const T &vector)
{
    for (int i = 0; i < vector.Size(); i++)
    {
        std::cout << vector[i] << std::endl;
    }

    std::cout << "------------------" << std::endl;
}

template <>
void PrintVector(const Vector<Object> &vector)
{
    for (int i = 0; i < vector.Size(); i++)
    {
        std::cout << vector[i].x << " " << vector[i].y << " " << vector[i].z << std::endl;
    }

    std::cout << "------------------" << std::endl;
}

int main()
{
    //   Vector<std::string> vec;
    //   vec.PushBack("union tsert");
    //   vec.PushBack("caoxiansheng");
    //   vec.PushBack("today is Thursday!");

    Vector<Object> vec;
    // vec.PushBack(Object(1.0f));
    // vec.PushBack(Object(2, 3, 4));
    // vec.PushBack(Object());

    std::cout << "----------------- EmplaceBack -----------------" << std::endl;
    vec.EmplaceBack(1.0f);
    vec.EmplaceBack(2, 3, 4);
    vec.EmplaceBack(1, 5, 7);
    vec.EmplaceBack();
    PrintVector(vec);
    vec.PopBack();
    vec.PopBack();
    PrintVector(vec);

    vec.EmplaceBack(5, 7, 9);
    vec.EmplaceBack(5, 2, 0);
    PrintVector(vec);
    vec.Clear();
    vec.EmplaceBack(2, 3, 4);
    vec.EmplaceBack(1, 5, 7);
    PrintVector(vec);

    Vector<std::string> vecstr;
    vecstr.EmplaceBack("caoxiansheng");
    vecstr.EmplaceBack("today!");
    vecstr.PushBack("testesa");
    vecstr.PushBack("hahah");

    for (Vector<std::string>::Iterator it = vecstr.begin(); it != vecstr.end(); it++)
    {
        std::cout << "---- " << *it << std::endl;
    }
    PrintVector(vecstr);
    std::cin.get();
}
